﻿using EnvSafe.Expression;
using Heroius.Extension;
using Heroius.Files;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using Heroius.Extension.WPF;
using Heroius.Extension.Desktop;

namespace IEPI.BIATranscribe
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public MainWindow()
        {
            InitializeComponent();
            Closing += MainWindow_Closing;

            Current = new Project();
            silo = new EntitySilo() { AutoStore = false, Recursion = true };

            DiaOpen = new OpenFileDialog() { Filter = "BIA Transcribe Project|*.btp" };
            DiaSave = new SaveFileDialog() { Filter = "BIA Transcribe Project|*.btp" };
            DiaExport = new SaveFileDialog() { Filter = "CSV|*.csv" };

            PvMe.PointPopping += PvMe_PointPopping;
            PvMe.PositionRequestChanged += PvMe_PositionRequestChanged;

            var op = new EnvSafe.Expression.FlexibleOperatorFactory();
            op.Factorys.Add(new OperatorFactory());
            op.Factorys.Add(new ExtOperatorFactory());
            ExpCore = new Interpreter(op);
            ExpCore.RegistCommonSymbolAndVariableMapping();

            DataContext = this;
        }

        /// <summary>
        /// 为文件IO对话框准备有效初始目录
        /// </summary>
        /// <param name="origin"></param>
        /// <returns></returns>
        string GetEffectFolder(string origin)
        {
            if (!string.IsNullOrWhiteSpace(origin))
            {
                var real = Environment.ExpandEnvironmentVariables(origin);
                if (Directory.Exists(real))
                {
                    return real;
                }
            }
            return App.RootPath;
        }

        /// <summary>
        /// 更新窗体标题，附加配置文件信息
        /// </summary>
        /// <param name="projHint"></param>
        void UpdateTitle(string projHint)
        {
            if (string.IsNullOrWhiteSpace(projHint))
                Title = "BIA 拓写工具";
            else
                Title = $"BIA 拓写工具 - {projHint}";
        }

        private void MainWindow_Closing(object sender, CancelEventArgs e)
        {
            if (MessageBox.Show("关闭窗体将丢失未保存的更改，确定已保存必要内容并且继续吗？\r\n点击 取消 放弃关闭并继续操作。", "提示", MessageBoxButton.OKCancel, MessageBoxImage.Information) == MessageBoxResult.Cancel)
            {
                e.Cancel = true;
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        void RaisePropertyChangedEvent(string PropertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
        }

        EntitySilo silo;

        OpenFileDialog DiaOpen;
        SaveFileDialog DiaSave;

        private void MiOpen_Click(object sender, RoutedEventArgs e)
        {
            DiaOpen.InitialDirectory = GetEffectFolder(Properties.Settings.Default.RecentO);
            if (DiaOpen.ShowDialog() == true)
            {
                Properties.Settings.Default.RecentO = DiaOpen.GetDirectory();
                Properties.Settings.Default.Save();
                silo.Load(DiaOpen.FileName);
                silo.Fetch("proj", Current);
                Current.DocPages.Clear();
                //手动载入集合和字典
                var copy = silo.InstanceStoresCopy;
                for (int i = 0; ; i++)
                {
                    var ikey = $"proj.DocPages.{i}";
                    if (silo.ContainsInstanceKey(ikey))
                    {
                        PageInfo newpage = new PageInfo();
                        silo.Fetch(ikey, newpage);
                        //数据
                        var dkeysinfo = copy.Where(kvp => kvp.Key.StartsWith($"{ikey}.Data.") && kvp.Key.EndsWith(".Key"));
                        if (dkeysinfo != null)
                            foreach (var item in dkeysinfo)
                            {
                                var vikey = $"{ikey}.Data.{item.Key.Split('.')[4]}.Value";
                                if (!string.IsNullOrWhiteSpace(copy[vikey].Value))
                                {
                                    newpage.Data.Add(item.Value.Value, copy[vikey].Value);
                                }
                            }
                        Current.DocPages.Add(newpage);
                    }
                    else break;
                }

                //检查设置有效路径
                var r2opath = PathHelper.RelativeToObsolete(Environment.ExpandEnvironmentVariables(Current.TargetPath), App.RootPath);
                var opath = Environment.ExpandEnvironmentVariables(Current.ObsTargetPath);
                if (Directory.Exists(opath)) Current.EffectTargetPath = opath;
                else if (Directory.Exists(r2opath)) Current.EffectTargetPath = r2opath;
                else
                {
                    MessageBox.Show("未找到指定配置文件中的目标文档文件夹！");
                }
                Current.Validate();
                UpdateOperationState();
                UpdateTitle(DiaOpen.SafeFileName);
                TbTotalPageCnt.Text = $"/{Current.DocPages.Count}";
            }
        }

        private void MiSave_Click(object sender, RoutedEventArgs e)
        {
            DiaSave.InitialDirectory = GetEffectFolder(Properties.Settings.Default.RecentS);
            if (DiaSave.ShowDialog() == true)
            {
                //特殊处理HeadText因其编辑框在点击菜单时不丢失焦点，以致不能更新源
                TbHeadText.GetBindingExpression(TextBox.TextProperty).UpdateSource();
                silo.Clear();
                silo.Store("proj", Current);
                silo.Save(DiaSave.FileName);
                //关于集合和字典：存储已支持
                UpdateTitle(DiaSave.SafeFileName);
                Properties.Settings.Default.RecentS = DiaSave.GetDirectory();
                Properties.Settings.Default.Save();
            }
        }

        private void BtnUpdate_Click(object sender, RoutedEventArgs e)
        {
            if (MessageBox.Show("更新配置将清空现有页面数据！是否继续？", "警告", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
            {
                var temp = new ProjectViewModel();
                temp.LoadFrom(Current);
                ConfigTargetWindow window = new ConfigTargetWindow(temp);
                if (window.ShowDialog() == true)
                {
                    Properties.Settings.Default.RecentB = temp.EffectTargetPath;
                    Properties.Settings.Default.Save();
                    Current.LoadFrom(temp);
                    UpdateOperationState();
                    TbTotalPageCnt.Text = $"/{Current.DocPages.Count}";
                }
            }
        }

        public Project Current { get { return App.Current; } set { App.Current = value; RaisePropertyChangedEvent("Current"); } }

        /// <summary>
        /// 指示是否能够编辑
        /// </summary>
        public bool OperationReady { get { return _OperationReady; } set { _OperationReady = value; RaisePropertyChangedEvent("OperationReady"); } }
        bool _OperationReady = false;
        /// <summary>
        /// 更新可编辑性
        /// </summary>
        void UpdateOperationState()
        {
            if (Current.DocPages.Count > 0)
            {
                OperationReady = true;
                NaviPage = Current.DocPages.First();
            }
            else
            {
                OperationReady = false;
            }
        }

        #region 页面导航

        public PageInfo NaviPage
        {
            get { return _NaviPage; }
            set
            {
                _NaviPage = value;
                //注意更新顺序敏感：先更新表格 再更新数据
                RaisePropertyChangedEvent("IsOddPage");
                RaisePropertyChangedEvent("CurrentPageDef");
                RaisePropertyChangedEvent("NaviPage");
                RaisePropertyChangedEvent("CanPre");
                RaisePropertyChangedEvent("CanNext");
                RaisePropertyChangedEvent("CurrentPageCode");
            }
        }
        PageInfo _NaviPage;

        public bool CanPre { get { if (NaviPage != null) return NaviPage.Code > 1; else return false; } }
        public bool CanNext { get { if (NaviPage != null) return NaviPage.Code < Current.DocPages.Count; else return false; } }

        private void BtnPre_Click(object sender, RoutedEventArgs e)
        {
            NaviPage = Current.DocPages.ElementAt(NaviPage.Code - 2);
        }

        private void BtnNext_Click(object sender, RoutedEventArgs e)
        {
            NaviPage = Current.DocPages.ElementAt(NaviPage.Code);
        }

        /// <summary>
        /// 指示当前页是否为奇数页
        /// </summary>
        public bool IsOddPage { get { if (NaviPage != null) return NaviPage.Code % 2 == 1; else return true; } }
        public int CurrentPageCode
        {
            get { if (NaviPage != null) return NaviPage.Code; else return 0; }
            set
            {
                if (value > 0 && value <= Current.DocPages.Count)
                {
                    NaviPage = Current.DocPages.ElementAt(value - 1);
                }
            }
        }

        public GridPageDef CurrentPageDef { get { return IsOddPage ? Current.OddPageDef : Current.EvenPageDef; } }

        private void ScrollViewer_Loaded(object sender, RoutedEventArgs e)
        {
            RaisePropertyChangedEvent("CanExport");
            if (CanExport) UpdateColSrc();
        }

        //在文件列表单击项目
        private void PageList_ButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            NaviPage = (sender as FrameworkElement).DataContext as PageInfo;
            TabMe.SelectedIndex = 1;
        }

        //直接输入页码
        private void Navi_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (e.Key == System.Windows.Input.Key.Enter)
            {
                var wantcode = (sender as TextBox).Text.As(0);
                if (wantcode >= 1 && wantcode <= Current.DocPages.Count)
                {
                    NaviPage = Current.DocPages.ElementAt(wantcode - 1);
                }
                else
                {
                    MessageBox.Show($"页码从 {1} 到 {Current.DocPages.Count}");
                }
            }
        }

        #endregion

        #region 页面控制

        /// <summary>
        /// 指示是否在编辑文档页定位
        /// </summary>
        public bool PageEditing { get { return _PageEditing; } set { _PageEditing = value; RaisePropertyChangedEvent("PageEditing"); } }
        bool _PageEditing;
        /// <summary>
        /// 编辑区域缩放比例
        /// </summary>
        public double EditorScale { get { return _EditorScale; } set { _EditorScale = value; RaisePropertyChangedEvent("EditorScale"); } }
        double _EditorScale = 0.5;

        #endregion

        #region 文档页定位

        Queue<Point3D> locPtrs = new Queue<Point3D>();
        string locTag;
        void BtnPageLocator_Click(object sender, RoutedEventArgs e)
        {
            locTag = (sender as Button).Tag.ToString();
            if (locTag == "END")
            {
                PvMe.EndRequest();
            }
            else
            {
                PvMe.BeginRequest();
            }
        }

        private void PvMe_PointPopping(PageView pv, Point3D ptr)
        {
            switch (locTag)
            {
                case "LT":
                    NaviPage.Trans.LeftTopX = ptr.X;
                    NaviPage.Trans.LeftTopY = ptr.Y;
                    break;
                case "LB":
                    NaviPage.Trans.LeftBottomX = ptr.X;
                    NaviPage.Trans.LeftBottomY = ptr.Y;
                    break;
                case "RT":
                    NaviPage.Trans.RightTopX = ptr.X;
                    NaviPage.Trans.RightTopY = ptr.Y;
                    break;
                case "RB":
                    NaviPage.Trans.RightBottomX = ptr.X;
                    NaviPage.Trans.RightBottomY = ptr.Y;
                    break;
            }
        }

        /// <summary>
        /// 折叠起来后自动结束请求
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Loc_Collapsed(object sender, RoutedEventArgs e)
        {
            PvMe.EndRequest();
        }

        private void PvMe_PositionRequestChanged(bool obj)
        {
            if (obj)
            {
                if (locTag == "END") TbState.Text = "尚未开始定位";
                else TbState.Text = $"正在定位：{ (locTag.Contains('L') ? "左" : "右")}{(locTag.Contains('T') ? "上" : "下")}角";
                GridState.Visibility = Visibility.Visible;
            }
            else
            {
                GridState.Visibility = Visibility.Collapsed;
            }
        }

        #endregion

        #region 表格导出

        /// <summary>
        /// 指示是否可以执行导出
        /// </summary>
        public bool CanExport { get { return Current.DocPages.Count(page => !page.Finished) == 0; } }

        SaveFileDialog DiaExport;

        public ObservableCollection<string> SrcCols { get; set; } = new ObservableCollection<string>();
        void UpdateColSrc()
        {
            SrcCols.Clear();
            SrcCols.Add("BLANK");
            for (int i = 0; i < Current.OddPageDef.ColumnCount; i++)
            {
                SrcCols.Add($"O{i}");
            }
            for (int i = 0; i < Current.EvenPageDef.ColumnCount; i++)
            {
                SrcCols.Add($"E{i}");
            }
        }

        public string SrcSelected { get; set; }
        public string DefSelected { get; set; }

        private void BtnAdd_Click(object sender, RoutedEventArgs e)
        {
            if (SrcSelected != null)
            {
                var item = new StringShell(SrcSelected);
                (LstDef.ItemsSource as ObservableCollection<StringShell>).Add(item);
                LstDef.GetBindingExpression(ListBox.ItemsSourceProperty).UpdateSource();
                LstDef.SelectedItem = item;
            }
            else MessageBox.Show("尚未选则项");
        }

        private void BtnRemove_Click(object sender, RoutedEventArgs e)
        {
            if (DefSelected != null)
            {
                (LstDef.ItemsSource as ObservableCollection<StringShell>).RemoveAt(LstDef.SelectedIndex);
                LstDef.GetBindingExpression(ListBox.ItemsSourceProperty).UpdateSource();
            }
            else MessageBox.Show("尚未选则项");
        }

        private void BtnUp_Click(object sender, RoutedEventArgs e)
        {
            if (DefSelected != null)
            {
                var idx = LstDef.SelectedIndex;
                if (idx > 0)
                {
                    (LstDef.ItemsSource as ObservableCollection<StringShell>).Move(idx, idx - 1);
                    LstDef.GetBindingExpression(ListBox.ItemsSourceProperty).UpdateSource();
                    LstDef.SelectedIndex = idx - 1;
                }
                else
                {
                    MessageBox.Show("已至队列顶端");
                }
            }
            else MessageBox.Show("尚未选则项");
        }

        private void BtnDown_Click(object sender, RoutedEventArgs e)
        {
            if (DefSelected != null)
            {
                var idx = LstDef.SelectedIndex;
                var src = (LstDef.ItemsSource as ObservableCollection<StringShell>);
                if (idx < src.Count)
                {
                    src.Move(idx, idx + 1);
                    LstDef.GetBindingExpression(ListBox.ItemsSourceProperty).UpdateSource();
                    LstDef.SelectedIndex = idx + 1;
                }
                else
                {
                    MessageBox.Show("已至队列底端");
                }
            }
            else MessageBox.Show("尚未选则项");
        }

        private void BtnConst_Click(object sender, RoutedEventArgs e)
        {
            var dia = new ConstWindow();
            if (dia.ShowDialog() == true)
            {
                var item = new StringShell($"C{dia.Constant}");
                (LstDef.ItemsSource as ObservableCollection<StringShell>).Add(item);
                LstDef.GetBindingExpression(ListBox.ItemsSourceProperty).UpdateSource();
                LstDef.SelectedItem = item;
            }
        }

        private void BtnVar_Click(object sender, RoutedEventArgs e)
        {
            var dia = new VarWindow();
            if (dia.ShowDialog() == true)
            {
                var item = new StringShell($"V{dia.Expression}");
                (LstDef.ItemsSource as ObservableCollection<StringShell>).Add(item);
                LstDef.GetBindingExpression(ListBox.ItemsSourceProperty).UpdateSource();
                LstDef.SelectedItem = item;
            }
        }

        Interpreter ExpCore;

        private void BtnExport_Click(object sender, RoutedEventArgs e)
        {
            var defc = (LstDef.ItemsSource as ObservableCollection<StringShell>).Select(shell => shell.Text).ToList();
            #region Validation
            if (Current.TellOE)
            {
                if (defc.Any(s => s[0] == 'O')) {
                    if (Current.OddPageDef.ColumnCount <= defc.Where(s => s[0] == 'O').Select(s => s.Substring(1).As<int>()).Max())
                    {
                        MessageBox.Show("根据导出定义，奇数页列过少，请仔细检查");
                        return;
                    } 
                }
                if (defc.Any(s => s[0] == 'E'))
                {
                    if (Current.EvenPageDef.ColumnCount <= defc.Where(s => s[0] == 'E').Select(s => s.Substring(1).As<int>()).Max())
                    {
                        MessageBox.Show("根据导出定义，偶数页列过少，请仔细检查");
                        return;
                    }
                }
            }
            else
            {
                if (Current.EvenPageDef.ColumnCount <= defc.Where(s => s[0] == 'O' || s[0] == 'E').Select(s => s.Substring(1).As<int>()).Max())
                {
                    MessageBox.Show("根据导出定义，列过少，请仔细检查");
                    return;
                }
            }
            #endregion
            #region Expression
            Dictionary<int, Procedure> exprocs = new Dictionary<int, Procedure>();
            for (int i = 0; i < defc.Count; i++)
            {
                if (defc[i].StartsWith("V"))
                {
                    exprocs.Add(i, ExpCore.GenerateProcedure(defc[i].Substring(1)));
                }
            }
            Dictionary<string, string> exparams = new Dictionary<string, string>();
            exparams.Add("RecIdx", "0");
            exparams.Add("PageIdx", "0");
            exparams.Add("RowIdx", "0");
            int recidx = 0;
            string strparam = "";
            for (int i = 0; i < Current.OddPageDef.ColumnCount; i++)
            {
                exparams.Add($"O{i}", "");
            }
            for (int i = 0; i < Current.EvenPageDef.ColumnCount; i++)
            {
                exparams.Add($"E{i}", "");
            }
            #endregion

            DiaExport.InitialDirectory = GetEffectFolder(Properties.Settings.Default.RecentE);
            if (DiaExport.ShowDialog() == true)
            {
                Properties.Settings.Default.RecentE = DiaExport.GetDirectory();
                Properties.Settings.Default.Save();
                using (StreamWriter sw = new StreamWriter(DiaExport.FileName, false, System.Text.Encoding.Default))
                {
                    sw.WriteLine(Current.HeadText);
                    var rowscount = Math.Max(Current.OddPageDef.RowCount, Current.EvenPageDef.RowCount);
                    if (Current.TellOE)
                    {
                        //note: 区分奇偶页录入时，必须保证既有奇数页又有偶数页
                        if(Current.DocPages.Count < 2)
                        {
                            MessageBox.Show("当前文档页数不足2页，无法区分奇偶页录入，请检查");
                            return;
                        }
                        exparams.Add("PageCount", (Current.DocPages.Count / 2).ToString());
                        for (int ip = 0; ip < Current.DocPages.Count; ip += 2) //两页并成一页录入
                        {
                            var pageo = Current.DocPages[ip];
                            var pagee = Current.DocPages[ip + 1];
                            for (int ir = 0; ir < rowscount; ir++)
                            {
                                var row = new string[defc.Count]; //新行空间
                                var emptymark = new bool[defc.Count]; //空白标记

                                exparams["PageIdx"] = ip.ToString();
                                exparams["RowIdx"] = ir.ToString();
                                for (int i = 0; i < Current.OddPageDef.ColumnCount; i++)
                                {
                                    pageo.Data.TryGetValue($"tb_{ir}_{i}", out strparam);
                                    exparams[$"O{i}"] = strparam;
                                }
                                for (int i = 0; i < Current.EvenPageDef.ColumnCount; i++)
                                {
                                    pagee.Data.TryGetValue($"tb_{ir}_{i}", out strparam);
                                    exparams[$"E{i}"] = strparam;
                                }

                                for (int ic = 0; ic < defc.Count; ic++)
                                {
                                    switch (defc[ic][0])
                                    {
                                        default:
                                        case 'B':
                                            row[ic] = "";
                                            emptymark[ic] = true;
                                            break;
                                        case 'O':
                                            {
                                                var itbc = defc[ic].Substring(1).As<int>();
                                                emptymark[ic] = !pageo.Data.TryGetValue($"tb_{ir}_{itbc}", out row[ic]);
                                            }
                                            break;
                                        case 'E':
                                            {
                                                var itbc = defc[ic].Substring(1).As<int>();
                                                emptymark[ic] = !pagee.Data.TryGetValue($"tb_{ir}_{itbc}", out row[ic]);
                                            }
                                            break;
                                        case 'C':
                                            row[ic] = defc[ic].Substring(1);
                                            emptymark[ic] = true;
                                            break;
                                        case 'V':
                                            row[ic] = exprocs[ic].Calculate(exparams);
                                            emptymark[ic] = string.IsNullOrWhiteSpace(row[ic]);
                                            break;
                                    }
                                }
                                if (!emptymark.All(m => m))
                                {
                                    sw.WriteLine(Heroius.Files.CSV.CsvHelper.WriteLine(row));
                                    recidx++;
                                    exparams["RecIdx"] = recidx.ToString();
                                }
                            }
                        }
                    }
                    else
                    {
                        exparams.Add("PageCount", Current.DocPages.Count.ToString());
                        for (int ip = 0; ip < Current.DocPages.Count; ip++) //每页均单独录入
                        {
                            var page = Current.DocPages[ip];
                            for (int ir = 0; ir < rowscount; ir++)
                            {
                                var row = new string[defc.Count];
                                var emptymark = new bool[defc.Count];

                                exparams["PageIdx"] = ip.ToString();
                                exparams["RowIdx"] = ir.ToString();
                                for (int i = 0; i < Current.OddPageDef.ColumnCount; i++)
                                {
                                    page.Data.TryGetValue($"tb_{ir}_{i}", out strparam);
                                    exparams[$"O{i}"] = strparam;
                                }
                                for (int i = 0; i < Current.EvenPageDef.ColumnCount; i++)
                                {
                                    page.Data.TryGetValue($"tb_{ir}_{i}", out strparam);
                                    exparams[$"E{i}"] = strparam;
                                }

                                for (int ic = 0; ic < defc.Count; ic++)
                                {
                                    switch (defc[ic][0])
                                    {
                                        default:
                                        case 'B':
                                            row[ic] = "";
                                            emptymark[ic] = true;
                                            break;
                                        case 'O':
                                        case 'E':
                                            {
                                                var itbc = defc[ic].Substring(1).As<int>();
                                                emptymark[ic] = !page.Data.TryGetValue($"tb_{ir}_{itbc}", out row[ic]);
                                            }
                                            break;
                                        case 'C':
                                            row[ic] = defc[ic].Substring(1);
                                            emptymark[ic] = true;
                                            break;
                                        case 'V':
                                            row[ic] = exprocs[ic].Calculate(exparams);
                                            emptymark[ic] = string.IsNullOrWhiteSpace(row[ic]);
                                            break;
                                    }
                                }
                                if (!emptymark.All(m => m))
                                {
                                    sw.WriteLine(Heroius.Files.CSV.CsvHelper.WriteLine(row));
                                    recidx++;
                                    exparams["RecIdx"] = recidx.ToString();
                                }
                            }
                        }
                    }
                    sw.Close();
                }
            }
        }

        #endregion

        private void MiOnline_Click(object sender, RoutedEventArgs e)
        {
            Process.Start(Properties.Settings.Default.OnlineUrl);
        }

        private void MiConfig_Click(object sender, RoutedEventArgs e)
        {
            new ConfigWindow().Show();
        }

        private void MiVer_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show($"V {System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()}\nPowered by Heroius", "当前版本", MessageBoxButton.OK, MessageBoxImage.Information);
        }


        #region 编辑提示

        private void BIAGrid_InBox(TextBox obj)
        {
            var loc = obj.TranslatePoint(new Point(0, 0), PvMe);
            var size = new Size(obj.ActualWidth, obj.ActualHeight);
            var rec = new Rect(loc, size);

            VisualBrush vb = new VisualBrush(PvMe);
            vb.Viewport = new Rect(0, 0, 1, 1);
            vb.ViewportUnits = BrushMappingMode.RelativeToBoundingBox;
            vb.Viewbox = rec;
            vb.ViewboxUnits = BrushMappingMode.Absolute;
            vb.Stretch = Stretch.Fill;
            PathOrigImage.Height = obj.ActualHeight;
            PathOrigImage.Width = obj.ActualWidth;
            PathOrigImage.Background = vb;

            TbHint.Text = obj.Text;

            GridHint.Visibility = Visibility.Visible;
        }

        private void BIAGrid_OutBox(TextBox obj)
        {
            GridHint.Visibility = Visibility.Collapsed;
        }

        private void BIAGrid_TextChanged(string obj)
        {
            TbHint.Text = obj;
        }

        #endregion

        private void BtnSetDoneAll_Click(object sender, RoutedEventArgs e)
        {
            foreach (var p in Current.DocPages)
            {
                p.Finished = true;
            }
        }

        private void BtnSetUndoneAll_Click(object sender, RoutedEventArgs e)
        {
            foreach (var p in Current.DocPages)
            {
                p.Finished = false;
            }
        }
    }
}
